﻿using UnityEngine;
using System.Collections.Generic;

namespace winS.Unity
{
    /// <summary>
    /// 函数更新器
    /// </summary>
    internal class FunctionUpdater : MonoBehaviour
    {
        internal readonly List<UpdateFunction> updateFunctionList = new List<UpdateFunction>();
        internal readonly List<UpdateFunction> waitAddUpdateFunctionList = new List<UpdateFunction>();
        internal readonly List<UpdateFunction> waitRemoveUpdateFunctionList = new List<UpdateFunction>();

        internal readonly List<LateUpdateFunction> lateUpdateFunctionList = new List<LateUpdateFunction>();
        internal readonly List<LateUpdateFunction> waitAddLateUpdateFunctionList = new List<LateUpdateFunction>();
        internal readonly List<LateUpdateFunction> waitRemoveLateUpdateFunctionList = new List<LateUpdateFunction>();

        internal readonly List<DelayCallFunction> delayCallFunctionList = new List<DelayCallFunction>();
        internal readonly List<DelayCallFunction> waitAddDelayCallFunctionList = new List<DelayCallFunction>();
        internal readonly List<DelayCallFunction> waitRemoveDelayCallFunctionList = new List<DelayCallFunction>();

        internal readonly List<RepeatCallFunction> repeatCallFunctionList = new List<RepeatCallFunction>();
        internal readonly List<RepeatCallFunction> waitAddRepeatCallFunctionList = new List<RepeatCallFunction>();
        internal readonly List<RepeatCallFunction> waitRemoveRepeatCallFunctionList = new List<RepeatCallFunction>();

        private float deltaTime;

        private void Update()
        {
            deltaTime = Time.deltaTime;

            RemoveDelayCallFunction();
            AddDelayCallFunction();
            UpdateDelayCallFunctionList();

            RemoveRepeatCallFunction();
            AddRepeatCallFunction();
            UpdateRepeatCallFunctionList();

            RemoveUpdateFunction();
            AddUpdateFunction();
            UpdateUpdateFunctionList();

        }
        private void LateUpdate()
        {
            RemoveLateUpdateFunction();
            AddLateUpdateFunction();
            UpdateLateUpdateFunctionList();
        }

        private void AddUpdateFunction() => AddFunction(waitAddUpdateFunctionList, updateFunctionList);
        private void RemoveUpdateFunction() => RemoveFunction(waitRemoveUpdateFunctionList, updateFunctionList);
        private void UpdateUpdateFunctionList() => UpdateFunction(updateFunctionList);

        private void AddLateUpdateFunction() => AddFunction(waitAddLateUpdateFunctionList, lateUpdateFunctionList);
        private void RemoveLateUpdateFunction() => RemoveFunction(waitRemoveLateUpdateFunctionList, lateUpdateFunctionList);
        private void UpdateLateUpdateFunctionList() => UpdateFunction(lateUpdateFunctionList);

        private void AddDelayCallFunction() => AddFunction(waitAddDelayCallFunctionList, delayCallFunctionList);
        private void RemoveDelayCallFunction() => RemoveFunction(waitRemoveDelayCallFunctionList, delayCallFunctionList);
        private void UpdateDelayCallFunctionList() => UpdateFunction(delayCallFunctionList);

        private void AddRepeatCallFunction() => AddFunction(waitAddRepeatCallFunctionList, repeatCallFunctionList);
        private void RemoveRepeatCallFunction() => RemoveFunction(waitRemoveRepeatCallFunctionList, repeatCallFunctionList);
        private void UpdateRepeatCallFunctionList() => UpdateFunction(repeatCallFunctionList);

        private void UpdateFunction<T>(List<T> runningFunctionList) where T : Function
        {
            foreach (var runningFunction in runningFunctionList)
            {
                if (runningFunction.functionState != FunctionState.Running) continue;
                runningFunction.Update(deltaTime);
            }
        }
        private void AddFunction<T>(List<T> waitAddFunctionList, List<T> runningFunctionList) where T : Function
        {
            foreach (var waitAddFunction in waitAddFunctionList)
            {
                if (waitAddFunction.functionState == FunctionState.WaitForAdd)
                {
                    waitAddFunction.functionState = FunctionState.Running;
                    runningFunctionList.Add(waitAddFunction);
                }
            }
            waitAddFunctionList.Clear();
        }
        private void RemoveFunction<T>(List<T> waitRemoveFunctionList, List<T> runningFunctionList) where T : Function
        {
            foreach (var waitRemoveFunction in waitRemoveFunctionList)
            {
                runningFunctionList.Remove(waitRemoveFunction);
                waitRemoveFunction.functionState = FunctionState.Removed;
            }
            waitRemoveFunctionList.Clear();
        }
    }
}